#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import sys
import pwd
import grp

from dws.commons.log_utils import log
from common.util.check_utils import is_valid_id
from common.common import output_result_file, exter_attack
from common.common_models import ActionResult
from common.const import ExecuteResultEnum, SubJobStatusEnum
from common.file_common import exec_lchown_dir_recursively
from dws.commons.const import CopyGenerateType
from dws.restore.archive_cloud_pre_job import ArchiveCloudPreJob
from dws.restore.archive_tape_pre_job import ArchiveTapePreJob
from dws.restore.common_pre_job import CommonPreJob
from dws.restore.parse_restore_job import ParseRestoreJobParam
from dws.restore.replication_pre_job import ReplicationPreJob


class PreJobFactory:
    @staticmethod
    @exter_attack
    def create_pre_job_obj(restore_param, input_pid):
        tmp_copy_type = restore_param.get_copy_type()
        if tmp_copy_type == "s3Archive":
            return ArchiveCloudPreJob(restore_param, input_pid)
        elif tmp_copy_type == "tapeArchive":
            return ArchiveTapePreJob(restore_param, input_pid)
        elif tmp_copy_type == "replication":
            return ReplicationPreJob(restore_param, input_pid)
        else:
            return CommonPreJob(restore_param, input_pid)


def gds_new_location_pre_job(restore_param):
    log.info(f"Restore gds to new location")
    data_path = restore_param.get_data_path()
    if not data_path:
        log.error("Get data path failed")
        return False
    copy_id = restore_param.get_source_backup_copy_id()
    if not copy_id:
        log.error("Get copy id failed")
        return False
    copy_path = os.path.join(data_path, copy_id)
    user, _ = restore_param.get_target_cluster_auth_info()
    if not user:
        log.error("Get target cluster auth user failed")
        return False
    try:
        group_id = pwd.getpwnam(str(user)).pw_gid
    except Exception as err:
        log.error(f"Get database user failed exception: {err}")
        return False
    database_user_group = grp.getgrgid(group_id).gr_name
    try:
        exec_lchown_dir_recursively(copy_path, user, database_user_group)
    except Exception as err_str:
        log.error(f"Fail to change user/group for {copy_path} for {err_str}")
        return False
    return True


if __name__ == "__main__":
    if len(sys.argv) < 2:
        log.error("Not enough input parameters.")
        sys.exit(1)
    pid = sys.argv[1]
    if not is_valid_id(pid):
        log.warn(f"pid is invalid")
        sys.exit(1)
    log.info(f"Start to execute pre job. pid: {pid}, task_id: {sys.argv[2]}")
    try:
        restore_job_param = ParseRestoreJobParam(pid)
    except Exception as e:
        log.error(f"Restore param init failed. pid: {pid}")
        sys.exit(1)

    copy_type = restore_job_param.get_copy_type()
    copy_generate_type = restore_job_param.get_copy_generate_type()  # GDS/ROACH
    if copy_generate_type == CopyGenerateType.INVALID_GENERATE_TYPE:
        output = ActionResult(code=ExecuteResultEnum.INTERNAL_ERROR, message="Failed to get copy generate type!")
        output_result_file(pid, output.dict(by_alias=True))
        sys.exit(1)
    # 如果是GDS类型的副本，默认前置任务成功
    if copy_generate_type == CopyGenerateType.GENERATE_BY_GDS and copy_type != "s3Archive":
        log.info(f"Start GDS restore pre job")
        output = ActionResult(code=ExecuteResultEnum.SUCCESS, message="")
        _, ret = restore_job_param.is_restore_new_cluster()
        if ret and not gds_new_location_pre_job(restore_job_param):
            log.error(f"Restore to new location pre job failed")
            output.code = ExecuteResultEnum.INTERNAL_ERROR
        output_result_file(pid, output.dict(by_alias=True))
        sys.exit(0)

    pre_job_obj = PreJobFactory.create_pre_job_obj(restore_job_param, pid)
    if pre_job_obj.do_pre_job():
        pre_job_obj.update_progress(SubJobStatusEnum.COMPLETED)
        output = ActionResult(code=ExecuteResultEnum.SUCCESS, message="")
        log.info("Execute prerequisite job successfully.")
    else:
        pre_job_obj.update_progress(SubJobStatusEnum.FAILED)
        output = ActionResult(code=ExecuteResultEnum.INTERNAL_ERROR, message="Fail to execute roach pre job")
        log.error("Execute prerequisite job failed.")
        output_result_file(pid, output.dict(by_alias=True))
    sys.exit(0)
